import logging
import asyncio
import time
from datetime import datetime, timedelta
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
from sqlalchemy.orm import Session
from app.database.database import SessionLocal
from app.database.models import BackupTask
import json
from app.services.backup_service import execute_backup
from sqlalchemy import and_

# 配置日志记录器
logger = logging.getLogger(__name__)

# 创建调度器
scheduler = AsyncIOScheduler()

async def run_backup_task(task_id: int):
    """执行单个备份任务
    
    Args:
        task_id: 备份任务ID
    """
    db = SessionLocal()
    try:
        # 获取任务信息
        task = db.query(BackupTask).filter(BackupTask.id == task_id).first()
        
        if not task:
            logger.error(f"备份任务 {task_id} 不存在")
            return
            
        if task.status == "running":
            logger.warning(f"备份任务 {task_id} 已在执行中，跳过此次调度")
            return
        
        logger.info(f"开始执行计划备份任务: {task_id}, 用户: {task.user_id}, 任务名称: {task.task_name}")
        
        # 执行备份
        start_time = time.time()
        result = execute_backup(
            db=db,
            task_id=task_id,
            user_id=task.user_id,
            force_full_backup=False
        )
        
        execution_time = time.time() - start_time
        logger.info(f"备份任务 {task_id} 执行完成，耗时 {execution_time:.2f} 秒，结果: {json.dumps(result)}")
        
    except Exception as e:
        logger.exception(f"执行备份任务 {task_id} 时发生错误: {str(e)}")
        # 更新任务状态为失败
        try:
            db.query(BackupTask).filter(BackupTask.id == task_id).update({"status": "failed"})
            db.commit()
        except Exception as commit_error:
            logger.error(f"更新备份任务状态失败: {str(commit_error)}")
            db.rollback()
    finally:
        db.close()

async def scan_scheduled_backup_tasks():
    """扫描并执行定时备份任务"""
    db = SessionLocal()
    try:
        logger.info("扫描定时备份任务...")
        
        # 获取所有启用的定时备份任务
        tasks = db.query(BackupTask).filter(
            and_(
                BackupTask.schedule_type != "manual",
                BackupTask.status != "running"
            )
        ).all()
        
        if not tasks:
            logger.info("没有找到定时备份任务")
            return
            
        logger.info(f"找到 {len(tasks)} 个定时备份任务")
        
        # 检查每个任务是否需要执行
        now = datetime.now()
        executed_count = 0
        
        for task in tasks:
            # 如果任务正在执行中，跳过
            if task.status == "running":
                continue
                
            # 判断是否需要执行
            should_execute = False
            
            # 对于每种计划类型，判断是否需要执行
            if task.schedule_type == "daily":
                # 如果上次备份时间为空，或者上次备份时间在24小时前，则执行
                if not task.last_backup_time or (now - task.last_backup_time) > timedelta(days=1):
                    should_execute = True
            
            elif task.schedule_type == "weekly":
                # 如果上次备份时间为空，或者上次备份时间在7天前，则执行
                if not task.last_backup_time or (now - task.last_backup_time) > timedelta(weeks=1):
                    should_execute = True
            
            elif task.schedule_type == "monthly":
                # 如果上次备份时间为空，或者上次备份时间在30天前，则执行
                if not task.last_backup_time or (now - task.last_backup_time) > timedelta(days=30):
                    should_execute = True
            
            # 执行任务
            if should_execute:
                logger.info(f"开始执行定时备份任务: {task.id}")
                # 创建异步任务
                asyncio.create_task(run_backup_task(task.id))
                executed_count += 1
        
        logger.info(f"已调度 {executed_count} 个定时备份任务")
        
    except Exception as e:
        logger.exception(f"扫描定时备份任务时发生错误: {str(e)}")
    finally:
        db.close()

def setup_backup_scheduler():
    """设置备份任务调度器"""
    try:
        # 添加定时扫描任务，每小时执行一次
        scheduler.add_job(
            scan_scheduled_backup_tasks,
            CronTrigger(hour='*', minute=0),  # 每小时整点执行
            id='scan_backup_tasks',
            replace_existing=True
        )
        
        # 启动调度器
        if not scheduler.running:
            scheduler.start()
            logger.info("备份任务调度器已启动")
        
        # 立即执行一次扫描，以便在应用启动时检查是否有需要执行的任务
        asyncio.create_task(scan_scheduled_backup_tasks())
        
    except Exception as e:
        logger.exception(f"设置备份任务调度器时发生错误: {str(e)}")

def shutdown_backup_scheduler():
    """关闭备份任务调度器"""
    if scheduler.running:
        scheduler.shutdown()
        logger.info("备份任务调度器已关闭") 